#ifndef _BundlerParser_H_
#define _BundlerParser_H_

/************************************************************************/
/* parse bundler.out file, get the View  and 3d point information*/
/* for each 3D point, find the list of 2d feature points */
/************************************************************************/
#include <fstream>
#include <omp.h>
#include <set>
#include <vector>

#include "Eigen/eigen"

#include "feature3d.h"
#include "picture.h"


/* 
	class to parse bundler file
	also able to load the .key files of all cameras
*/
class BundlerParser
{
private:
  // All_PICTUREs member include pictures and cameras
  AllPictures	mPictures;
  std::vector<Camera>	mCameras;
  std::vector<Feature3DInfo> mFeature_infos;
  
  // for localizer
  cv::Mat mDescriptorMat;
  std::vector<int> mMap2dTo3d;
  std::vector<int> mPoints3dCost;
  std::vector<Eigen::Vector3d> mPoints3D;

  std::string bundler_out;
  std::string key_path;
  std::string list_file;
  std::string feat_3d_info_file;
  std::string image_path;

  // load the feat and desc info 
  bool LoadFeatDesc(const std::string& key_path,
                    const std::string& list_file,
                    const std::string& image_path = "",
                    const bool load_only_query = false);
  
  // parse the bundler file
  // input parameter: the file name of the output file(bundler.out)
  // must call this after LoadFeatDesc
  bool ParseBundlerFile(const std::string& bundler_out, bool bLoad_feat_info = true);

  // save loaded feature 3d info into file, so next time can load from this file
  bool SaveFeatures3DInfo(const std::string& feat_3d_info_file) const;
  bool LoadFeatures3DInfo(const std::string& feat_3d_info_file);
  bool SaveFeatures3DInfoBin(const std::string& feat_3d_info_file) const;
  bool LoadFeatures3DInfoBin(const std::string& feat_3d_info_file);

public:
	// constructor
	BundlerParser();

  BundlerParser(const std::string& _bundler_out,
                const std::string& _key_path,
                const std::string& _list_file,
                const std::string& _feat_3d_info_file,
                const std::string& _image_path);

	~BundlerParser();

  // load Data function
  bool LoadData();

  void StatistisDistance(const std::string& file);
  inline uint64_t CalculateHammingDistance(const unsigned char* d1,
                                           const unsigned char* d2,
                                           int length = Descriptor::desc_legth);
  // clear all the data
  void ClearData();

  const cv::Mat& DescMat() const {
    return mDescriptorMat;
  }
  // get the total number of 2d feature
  size_t DescriptorNum() const {
    return mDescriptorMat.rows;
  }

  // return the number of bytes of descriptor
  size_t DescriptorLength() const {
    return mDescriptorMat.cols;
  }

  // get the 3d points
  const std::vector<Eigen::Vector3d>& Points3D() const {
    return mPoints3D;
  }
  size_t PointsNum() const {
    return mPoints3D.size();
  }

  const std::vector<int>& MapFeaturetoPoint3D() const {
    return mMap2dTo3d;
  }
  const std::vector<int>& Points3DCost() const {
    return mPoints3dCost;
  }

  const std::vector<Picture>& Pictures() const {
    return mPictures.Pictures();
  }
  size_t PictureNum() const {
    return mPictures.PictureNum();
  }
  
  void GetQueryPictures(std::vector<Picture>& pics) const;
  void GetQueryCameras(std::vector<Camera>& cams) const;

  const std::vector<Camera>& Cameras() const {
    return mCameras;
  }
  size_t CameraNum() const {
    return mCameras.size();
  }
};

#endif